package com.py.framework.service.impl;

import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletResponse;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.delegate.Expression;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.task.TaskDefinition;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.spring.ProcessEngineFactoryBean;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.py.framework.core.common.Page;
import com.py.framework.core.exception.ServiceException;
import com.py.framework.core.log.ExceptionLogger;
import com.py.framework.core.log.SystemLogger;
import com.py.framework.entity.OutGoingCondition;
import com.py.framework.entity.WorkFlowBus;
import com.py.framework.entity.WorkFlowOutGoing;
import com.py.framework.entity.WorkFlowRole;
import com.py.framework.entity.WorkFlowWrapper;
import com.py.framework.service.ActReviewService;
import com.py.framework.service.WorkFlowRoleService;
import com.py.framework.service.WorkFlowService;

/**
 * 流程审核Service实现
 * 
 * @author Leegern
 * @date 2018年5月23日
 */
@Service
public class ActReviewServiceImpl implements ActReviewService {

	private final String ACTIVITI_TYPE_STARTEVENT = "startEvent";

	private final String ACTIVITI_TYPE_ENDEVENT = "endEvent";

	private final String ACTIVITI_OUTGOING_NEXT = "下一步";

	private final String ACTIVITI_TYPE_USERTASK = "userTask";

	private final String ACTIVITI_TYPE_EXCLUSIVEGATEWAY = "exclusiveGateway";

	private final int ACTIVITI_NODE_LEVEL = 2;

	@Autowired
	private ProcessEngineFactoryBean processEngine;
	@Autowired
	private TaskService taskService;
	@Autowired
	private RuntimeService runtimeService;
	@Autowired
	private HistoryService historyService;
	@Autowired
	private RepositoryService repositoryService;
	@Autowired
	private WorkFlowService workflowService;
	@Autowired
	private WorkFlowRoleService wfRoleService;

	@Value("${wf.root.dir}")
	private String wfRootDir;

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.ActReviewService#queryActReviewDataList(com.py.
	 * framework.core.common.Page, long)
	 */
	@Override
	public List<WorkFlowWrapper> queryActReviewDataList(Page page, long currUserId, String startTime, String endTime,
			String processName) {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		List<WorkFlowWrapper> list = new ArrayList<WorkFlowWrapper>();
		List<Task> taskList = new ArrayList<Task>();
		int total = 0;
		String userId = String.valueOf(currUserId);
		WorkFlowWrapper model = null;
		WorkFlowBus workflow = null;
		List<WorkFlowRole> workFlowRoles = wfRoleService.getWorkFlowRoleByUserId(currUserId);
		// TODO 根据userId来查询似乎没用，是根据wfRoleKey来的
		TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(userId);

		// 加日期和流程名称字段查询
		if (null != processName && !processName.trim().equals("")) {
			taskQuery.processDefinitionNameLike(processName);
		}

		if (null != startTime && !startTime.trim().equals("")) {
			try {
				taskQuery.taskCreatedAfter(format.parse(startTime));
			} catch (ParseException e) {
				ExceptionLogger.error(e);
			}
		}

		if (null != endTime && !endTime.trim().equals("")) {
			try {
				taskQuery.taskCreatedBefore(format.parse(endTime));
			} catch (ParseException e) {
				ExceptionLogger.error(e);
			}
		}

		taskQuery.orderByTaskCreateTime().desc();

		List<Task> tasks = taskQuery.list();
		taskList.addAll(tasks);
		total = tasks.size();

		if (!CollectionUtils.isEmpty(workFlowRoles)) {
			// TaskQuery taskGroupQuery =
			// taskService.createTaskQuery().taskCandidateGroup(wfRoleKey)
			// .orderByTaskCreateTime().desc();
			// 一个用户多个工作流角色

			List<String> wfRoleKeys = new ArrayList<String>();
			for (WorkFlowRole workFlowRole : workFlowRoles) {

				String wfRoleKey = workFlowRole.getKey();
				wfRoleKeys.add(wfRoleKey);

			}

			// 过滤bug fix
			TaskQuery taskGroupQuery = taskService.createTaskQuery().taskCandidateGroupIn(wfRoleKeys)
					.orderByTaskCreateTime().desc();

			if (null != processName && !processName.trim().equals("")) {
				taskGroupQuery.processDefinitionNameLike(processName);
			}

			if (null != startTime && !startTime.trim().equals("")) {
				try {
					taskGroupQuery.taskCreatedAfter(format.parse(startTime));
				} catch (ParseException e) {
					ExceptionLogger.error(e);
				}
			}

			if (null != endTime && !endTime.trim().equals("")) {
				try {
					taskGroupQuery.taskCreatedBefore(format.parse(endTime));
				} catch (ParseException e) {
					ExceptionLogger.error(e);
				}
			}

			List<Task> taskGroupList = taskGroupQuery.list();
			taskList.addAll(taskGroupList);
			total = total + taskGroupList.size();
		}
		int num = total;
		// 过滤无效数据
		for (int i = 0; i < total; i++) {
			Task task = taskList.get(i);
			String procId = task.getProcessInstanceId();
			// 获取页面要展示的业务数据
			workflow = workflowService.findActByProcId(procId);
			if (null == workflow) {
				SystemLogger.info("发现工作流实例ID 与 业务数据 未对应上！！！");
				// 因为该条数据已经被过滤掉了，所以返回数据总条数也要减去1
				num = num - 1;
				continue;
			}
			model = new WorkFlowWrapper();
			BeanUtils.copyProperties(workflow, model);

			// 添加必要的数据
			model.setTaskId(task.getId());
			model.setExecutionId(task.getExecutionId());

			ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
					.processDefinitionId(task.getProcessDefinitionId()).singleResult();

			// 需要展示的数据
			model.setProcessDefinitionName(processDefinition.getName());
			model.setTaskName(task.getName());
			model.setTaskCreateTime(task.getCreateTime());

			list.add(model);
		}

		// 根据分页参数截取list
		List<WorkFlowWrapper> workList = new ArrayList<WorkFlowWrapper>();
		// 分页bugfix
		page.setTotalCount(num);
		// TODO 做前端分页
		int firstResult = (page.getCurrentPage() - 1) * page.getPageSize(), maxResults = page.getPageSize();
		for (int i = firstResult; i < (firstResult + maxResults) && i < num; i++) {
			workList.add(list.get(i));
		}
		return workList;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.py.framework.service.ActReviewService#queryActReviewById(long)
	 */
	@Override
	public Object queryActReviewById(long businessId) {

		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.ActReviewService#getHistoryComment(java.lang.
	 * String)
	 */
	@Override
	public List<Map<String, Object>> getHistoryComment(String procId) {
		List<Map<String, Object>> result = new ArrayList<>();
		if (StringUtils.isNotBlank(procId)) {
			List<Comment> comments = taskService.getProcessInstanceComments(procId);
			Map<String, Object> object = null;
			Comment comment = null;
			String fullMsg = "";
			String[] array = null;
			int size = comments.size();
			for (int i = size - 1; i >= 0; i--) {
				object = new HashMap<String, Object>();
				comment = comments.get(i);
				fullMsg = comment.getFullMessage();
				array = org.springframework.util.StringUtils.delimitedListToStringArray(fullMsg, "!@#");
				if (array.length == 3) {
					object.put("taskName", array[0]);
					object.put("userName", array[1]);
					object.put("comment", array[2]);
				}
				object.put("time", comment.getTime());
				result.add(object);
			}
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.py.framework.service.ActReviewService#getActNextNode(java.lang.
	 * String)
	 */
	@Override
	public List<WorkFlowOutGoing> getActNextNode(String taskId) {
		// 根据taskId获取 processDefinitionId和当前activitiId
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		if (null != task) {
			String excId = task.getExecutionId();
			if (StringUtils.isNoneBlank(excId)) {
				ExecutionEntity execution = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(excId)
						.singleResult();
				String currentActivityId = execution.getActivityId();
				return findNextOutGoings(task.getProcessDefinitionId(), false, currentActivityId);
			}
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.py.framework.service.ActReviewService#examineTask(java.util.Map)
	 */
	@Override
	public void examineTask(Map<String, Object> params) {
		String userId = String.valueOf(params.get("userId"));
		String taskId = String.valueOf(params.get("taskId"));
		String procId = String.valueOf(params.get("procId"));
		String comment = String.valueOf(params.get("comment"));
		String paramName = String.valueOf(params.get("paramName"));
		String paramValue = String.valueOf(params.get("paramValue"));

		String currUserId = String.valueOf(params.get("currUserId"));
		String currRealName = String.valueOf(params.get("currRealName"));

		try {
			Task thisTask = taskService.createTaskQuery().taskId(taskId).singleResult();
			String taskName = thisTask.getName();

			// 添加批注
			taskService.addComment(taskId, procId, taskName + "!@#" + currRealName + "!@#" + comment);

			// 先完成任务
			Map<String, Object> variables = new HashMap<String, Object>();
			if (StringUtils.isNotBlank(paramName)) {
				variables.put(paramName, paramValue);
			}

			// 为了防止第一次没有指定办理人，所以先判断一下该任务是否已经分配给了某人
			if (StringUtils.isBlank(thisTask.getAssignee())) {
				taskService.setAssignee(taskId, String.valueOf(currUserId));
			}

			taskService.complete(taskId, variables);

			// 这里需要注意一下，先判断流程是否结束，如果结束就更新下控制表里的字段，否则再分配下一位办理人
			ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(procId)
					.singleResult();

			/*
			 * 20170302 重新修改了流程结束的监听机制，暂时不用动态注入监听器的方式了，改为下面根据历史记录的数据进行判断
			 */
			HistoricActivityInstance hai = historyService.createHistoricActivityInstanceQuery()
					.processInstanceId(procId).activityType("endEvent").singleResult();
			if (null != hai) {
				String activityName = hai.getActivityName();
				WorkFlowBus workflow = workflowService.findActByProcId(procId);

				// 流程结束后，更新一下流程控制表中的流程状态
				// 如果是指定的字符则表示审核通过
				if ("pass".equals(activityName)) {
					workflow.setProStatus(3);
				} else {
					workflow.setProStatus(4);
				}
				// 更改工作流状态为关闭
				workflow.setActStatus(2);
				workflow.setDealStatus(2);
				workflow.setFinishTime(new Timestamp(System.currentTimeMillis()));
				workflow.setUpdateTime(new Timestamp(System.currentTimeMillis()));
				workflow.setRemark(comment);
				workflowService.updateWorkFlowBus(workflow);
			}

			if (null == processInstance) {
				// // 流程结束后，更新一下流程控制表中的流程状态
				// TGsWorkflow workflow = workflowService.findByProcId(procId);
				// String status = workflow.getStatus();
				// if (!"Y".equals(status)) {
				// workflow.setStatus("N");
				// }
				//// workflow.setId(Integer.valueOf(tId));
				// workflow.setFinish_time(new Date());
				//
				// workflowService.updateTGsWorkflow(workflow);
			} else {
				if (!"0".equals(userId)) {
					// 获取任务，并分配办理人
					Task task = taskService.createTaskQuery().processInstanceId(procId).singleResult();
					taskService.setAssignee(task.getId(), userId);
				}
			}
		} catch (Exception e) {
			ExceptionLogger.error(e);
			throw new ServiceException("examine task error.");
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.py.framework.service.ActReviewService#getFlowChart(java.lang.String)
	 */
	@Override
	public void getFlowChart(String executionId) {

		HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
				.getResponse();

		ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(executionId)
				.singleResult();
		BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
		List<String> activeActivityIds = runtimeService.getActiveActivityIds(executionId);

		// 使用spring注入引擎请使用下面的这行代码
		ProcessEngineConfiguration processEngineConfiguration = processEngine.getProcessEngineConfiguration();
		Context.setProcessEngineConfiguration((ProcessEngineConfigurationImpl) processEngineConfiguration);

		ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();
		InputStream imageStream = diagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds,
				new ArrayList<String>(), "宋体", "宋体", null, 1.0);
		try {
			response.setHeader("Content-type", "image/png");
			OutputStream out = response.getOutputStream();
			// 输出资源内容到相应对象
			byte[] b = new byte[1024];
			int len;
			while ((len = imageStream.read(b, 0, 1024)) != -1) {
				out.write(b, 0, len);
			}
			out.close();
		} catch (Exception e) {
			ExceptionLogger.error(e);
		}

	}

	/**
	 * 根据processDefinitionId及currentActivityId查找所有流向
	 * 
	 * @param processDefinitionId
	 * @param isStart
	 *            当isStart=false时，currentActivityId生效
	 * @param currentActivityId
	 * @return
	 */
	private List<WorkFlowOutGoing> findNextOutGoings(String processDefinitionId, boolean isStart,
			String currentActivityId) {
		// 获取流程定义
		ProcessDefinitionEntity def = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
				.getDeployedProcessDefinition(processDefinitionId);
		List<ActivityImpl> activitiList = def.getActivities();
		// 遍历所有节点
		String activityType = "";
		ActivityImpl currentActivity = null;

		List<WorkFlowOutGoing> wfList = null;

		for (ActivityImpl activityImpl : activitiList) {
			Map<String, Object> map = activityImpl.getProperties();
			activityType = (String) map.get("type");

			// 如果是开始 开始节点，需要特殊处理
			if (isStart) {
				if (!ACTIVITI_TYPE_STARTEVENT.equalsIgnoreCase(activityType)) {
					continue;
				}
				// 找到开始节点
				currentActivity = activityImpl;
				// 找到节点全部可能走向
				wfList = findNextOutTransitions(currentActivity);
				break;
			}
			// 寻找到当前节点
			if (StringUtils.equals(activityImpl.getId(), currentActivityId)) {
				currentActivity = activityImpl;
				wfList = findNextOutTransitions(currentActivity);
				break;
			}
		}
		return wfList;
	}

	/**
	 * 找到下已节点的流程，目前只支持 userTask、exclusiveGateway、endEven,exclusiveGateway只支持1层
	 * 
	 * @param currentActivity
	 * @return
	 */
	private List<WorkFlowOutGoing> findNextOutTransitions(ActivityImpl currentActivity) {
		List<WorkFlowOutGoing> nextlist = new ArrayList<WorkFlowOutGoing>();
		// 只支持二级遍历，即Gateway连续两个
		// -- 第一次遍历
		List<PvmTransition> outTransitions = currentActivity.getOutgoingTransitions();
		nextlist = findLvOutTransitions(outTransitions, 1);
		return nextlist;
	}

	/**
	 * 递归查询下一流向List
	 * 
	 * @param outTransitions
	 *            走向对象
	 * @param level
	 *            当前层级，目前ACTIVITI_NODE_LEVEL 只支持到2
	 * @return
	 */
	private List<WorkFlowOutGoing> findLvOutTransitions(List<PvmTransition> outTransitions, int level) {

		String activityType = null; // 节点类型
		String candidateGroup = null; // 节点参与角色
		String activityName = null; // 节点名称
		String outGoingName = null; // 去向
		TaskDefinition taskDefine = null;

		List<WorkFlowOutGoing> lvList = new ArrayList<WorkFlowOutGoing>();
		List<WorkFlowOutGoing> nextList = new ArrayList<WorkFlowOutGoing>();

		Set<Expression> candidateGroupsExps = null;
		WorkFlowOutGoing outGoing = null;
		for (PvmTransition tr : outTransitions) {
			candidateGroup = "";
			OutGoingCondition condition = null;
			outGoing = new WorkFlowOutGoing();

			// 获取线路的终点节点
			PvmActivity ac = tr.getDestination();

			activityType = (String) ac.getProperty("type");
			activityName = (String) ac.getProperty("name");
			taskDefine = (TaskDefinition) ac.getProperty("taskDefinition");

			// 获取条件判断
			String conditionText = (String) tr.getProperty("conditionText");
			if (StringUtils.isNotEmpty(conditionText)) {
				// ${gateway1 == 'true'}
				condition = new OutGoingCondition();

				// condition.setParamName(paramName);
				// 解析字符
				int posFront = conditionText.indexOf("{");
				int posEnd = conditionText.indexOf("}");
				int posExpress = 0;
				if (conditionText.contains("==")) {
					posExpress = conditionText.indexOf("==");

					String paramName = conditionText.substring(posFront + 1, posExpress).trim();
					String paramValue = conditionText.substring(posExpress + 2, posEnd).trim();
					if (paramValue.indexOf("'") != -1) {
						paramValue = paramValue.substring(1, paramValue.length() - 1);
					}

					condition.setParamName(paramName);
					condition.setParamValue(paramValue);
					condition.setParamExpress(OutGoingCondition.CONDITION_EXPRESS_EQ);
				}
				outGoing.setCondition(condition);
			}

			// 去向名称，即流程图 线上面的字
			outGoingName = (String) tr.getProperty("name");

			/*
			 * 根据不同节点类型，选择进行二级遍历 ACTIVITI_TYPE_USERTASK ： 用户任务只需一级遍历，获取其
			 * 角色信息用于选择人 ACTIVITI_TYPE_ENDEVENT ： 结束节点只需一级遍历，返回结束标识即可
			 * ACTIVITI_TYPE_EXCLUSIVEGATEWAY ：选择节点 需要获取其所有下级走向，下级走向的节点描述及角色信息
			 * 用于选择走向及人
			 */
			if (ACTIVITI_TYPE_USERTASK.equalsIgnoreCase(activityType)) {
				candidateGroupsExps = taskDefine.getCandidateGroupIdExpressions();
				for (Expression candidateGroupExp : candidateGroupsExps) {
					candidateGroup += candidateGroupExp.getExpressionText() + ",";
				}
				// ACTIVITI_TYPE_USERTASK节点，默认将多个角色以逗号分隔存储
				if (candidateGroup.length() > 1) {
					outGoing.setCandidateGroup(candidateGroup.substring(0, candidateGroup.length() - 1));
				} else {
					outGoing.setCandidateGroup(null);
				}

				outGoing.setType(ACTIVITI_TYPE_USERTASK);

				// ACTIVITI_TYPE_USERTASK节点，如果未填写去向名称，则默认为“下一步”
				outGoingName = StringUtils.isEmpty(outGoingName) ? ACTIVITI_OUTGOING_NEXT : outGoingName;

				// 设置节点名称
				outGoing.setActivityName(activityName);
				// 设置流向名称
				outGoing.setOutGoing(outGoingName);
				lvList.add(outGoing);
			} else if (ACTIVITI_TYPE_ENDEVENT.equalsIgnoreCase(activityType)) {
				outGoing.setType(ACTIVITI_TYPE_ENDEVENT);

				if (level == 1) {
					// ACTIVITI_TYPE_ENDEVENT 默认为“下一步”
					outGoingName = ACTIVITI_OUTGOING_NEXT;
				} else {
					// ACTIVITI_TYPE_USERTASK节点，如果未填写去向名称，则默认为“下一步”
					outGoingName = StringUtils.isEmpty(outGoingName) ? ACTIVITI_OUTGOING_NEXT : outGoingName;
				}

				// 设置节点名称
				outGoing.setActivityName(activityName == null ? "结束" : activityName);
				// 设置流向名称
				outGoing.setOutGoing(outGoingName);
				lvList.add(outGoing);
			} else if (ACTIVITI_TYPE_EXCLUSIVEGATEWAY.equalsIgnoreCase(activityType)) {

				if (level >= ACTIVITI_NODE_LEVEL) {
					// 设置节点名称
					outGoing.setActivityName(activityName == null ? "自动判断" : activityName);
					// 设置流向名称
					outGoing.setOutGoing(outGoingName);
					lvList.add(outGoing);
				} else {
					List<PvmTransition> nextLvOutTransitions = ac.getOutgoingTransitions();
					nextList = findLvOutTransitions(nextLvOutTransitions, ++level);

					if (nextList != null) {
						lvList.addAll(nextList);
					}
				}
			}
		}
		return lvList;
	}
}